/*
 * bbb.c
 *
 *  Created on: Nov 25, 2019
 *      Author: Standa
 */

#include "bbb.h"
#include "stm32f0xx_it.h"
#include <stdint.h>
#include "measurement.h"
#include "syndet.h"
#include "main.h"
#include "tim.h"
#include "qfplib.h"


#define BBB_VBATMEAS_THRESHOLD_V	2.7f
#define BBB_VBATMULTIPLIER			3.0f
#define BBB_UPDATEINTERVAL_MS		25
#define BBB_LONGPRESS_MS			400
#define BBB_DOUBLEPRESS_MS			400


static meas_InputTd AnalogInputReadings;
static float VBat = 0;
static float Temp = 0;
static uint8_t BuzzerActive = 0;
static uint32_t LastBtnEvtUpdateTimestamp = 0;


float bbb_GetVbat(void){
	return VBat;
}

float bbb_GetTemp(void){
	return Temp;
}


bbb_BtnTd BtnUp = {3.05, 3.3}, BtnDn = {0.2, 0.95}, BtnBoth = {2.6, 2.95};

static bbb_BtnTd* BtnList[] = {&BtnUp, &BtnDn};


/*
 * Initialize button, buzzer, battery module
 */
void bbb_Init(void){
	  LL_TIM_OC_SetMode(TIM3, LL_TIM_CHANNEL_CH4, LL_TIM_OCMODE_PWM1);
	  LL_TIM_EnableCounter(TIM3);
}



/*
 * Updates all bbb readings. Works only when buzzer, measurement is not active. Handles debouncing.
 * Returns when buttons are updated
 */
uint8_t bbb_UpdateBtns(void){
	uint8_t AnyButtonPressed = 0;
	bbb_BtnTd* pBtn;


	if( ( GetTick() < LastBtnEvtUpdateTimestamp + BBB_UPDATEINTERVAL_MS) || (sd_GetMeasurementStatus()) || (BuzzerActive) ){
		for(uint8_t i=0; i< UT_SIZEOFARRAY(BtnList); i++){
			pBtn = BtnList[i];
			if(pBtn == 0) continue;

			pBtn->PrevBtnEvt = bbb_EvtTd_None;
		}
	}





	LastBtnEvtUpdateTimestamp = GetTick();														//Store last update timestamp
	if(meas_ReadAnalogInputsSync_V(&AnalogInputReadings) != err_Td_Ok) return 0;				//Convert all analog inputs




	for(uint8_t i=0; i< UT_SIZEOFARRAY(BtnList); i++){
		pBtn = BtnList[i];
		if(pBtn == 0) continue;

		if(AnalogInputReadings.VBBB_V < pBtn->LowerThreshold || AnalogInputReadings.VBBB_V > pBtn->UpperThreshold){
			if(pBtn->PrevBtnState != 0){																//If button state is different from last reading (released)
				pBtn->PrevBtnState = 0;																//Save current state
				uint32_t ReleasedToReleased = GetTick() - pBtn->ReleasedTimestamp;								//Delay between this and previous release (falling edge to falling edge)
				pBtn->ReleasedTimestamp = GetTick();
				pBtn->StateChangeInterval = GetTick() - pBtn->PrevBtnStateTimestamp;						//Calculate press duration
				pBtn->PrevBtnStateTimestamp = GetTick();												//Update state change timestamp

				if(pBtn->StateChangeInterval > BBB_DOUBLEPRESS_MS){
					pBtn->SingleReleasedEnsuredTimestamp = 0;
					pBtn->PrevBtnEvt = bbb_EvtTd_LongReleased;
				}
				else if(ReleasedToReleased < BBB_DOUBLEPRESS_MS){
					pBtn->SingleReleasedEnsuredTimestamp = 0;
					pBtn->PrevBtnEvt =  bbb_EvtTd_DoubleReleased;
				}
				else{
					pBtn->SingleReleasedEnsuredTimestamp = GetTick()+BBB_DOUBLEPRESS_MS;
					pBtn->PrevBtnEvt =  bbb_EvtTd_Released;
				}
			}
			else{
				if(pBtn->SingleReleasedEnsuredTimestamp && GetTick() > pBtn->SingleReleasedEnsuredTimestamp){
					pBtn->SingleReleasedEnsuredTimestamp = 0;
					pBtn->PrevBtnEvt =  bbb_EvtTd_SingleReleased;
				}
				else{
					pBtn->PrevBtnEvt = bbb_EvtTd_Low;
				}
			}
		}
		else{
			AnyButtonPressed = 1;

			if(pBtn->PrevBtnState != 1){					//If button state is different from last reading (now is pressed, before was not pressed)
				pBtn->PrevBtnState = 1;					//Save current state
				pBtn->StateChangeInterval = GetTick() - pBtn->PrevBtnStateTimestamp;
				pBtn->PrevBtnStateTimestamp = GetTick();
				pBtn->PrevBtnEvt = bbb_EvtTd_Pressed;
			}
			else{
				pBtn->PrevBtnEvt = bbb_EvtTd_High;
			}
		}






	}


	if(AnyButtonPressed == 0) VBat = qfp_fmul( AnalogInputReadings.VBBB_V, BBB_VBATMULTIPLIER );	//If no button is pressed update battery voltage reading

	return 1;
}


/*
 * Beeps the buzzer with specified tone (0 = off, 1=low, 2=medium, 3=high) for specified time in ms
 * tone 0 with time is just delay
 */
void bbb_Beep(bbb_ToneTd tone, uint16_t time){
	volatile uint32_t Stop = GetTick() + time;

	BuzzerActive = 1;
	if(tone>3) tone=3;

	if(tone>0){
		LL_GPIO_SetPinMode(VBAT_GPIO_Port, VBAT_Pin, LL_GPIO_MODE_ALTERNATE);
		LL_GPIO_SetAFPin_0_7(VBAT_GPIO_Port, VBAT_Pin, LL_GPIO_AF_1);
		LL_GPIO_SetPinOutputType(VBAT_GPIO_Port, VBAT_Pin, LL_GPIO_OUTPUT_PUSHPULL);
		//Start timer
		LL_TIM_SetAutoReload(TIM3, 1200 - tone * 200);
		LL_TIM_OC_SetCompareCH4(TIM3, (1200 - tone * 200)>>1);
		LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH4);
	}

	while(1) if(GetTick() > Stop) break;

	if(tone>0){
		//Stop timer
		LL_GPIO_SetPinMode(VBAT_GPIO_Port, VBAT_Pin, LL_GPIO_MODE_ANALOG);
		LL_GPIO_SetPinPull(VBAT_GPIO_Port, VBAT_Pin, LL_GPIO_PULL_NO);
		LL_TIM_CC_DisableChannel(TIM3, LL_TIM_CHANNEL_CH4);
	}


	BuzzerActive = 0;
}


void bbb_Melody2(uint8_t tone1, uint8_t tone2, uint16_t time){
	  bbb_Beep(tone1, time);
	  bbb_Beep(0, time);
	  bbb_Beep(tone2, time);
	  bbb_Beep(0, time);
}


void bbb_Melody3(uint8_t tone1, uint8_t tone2, uint8_t tone3, uint16_t time){
	  bbb_Beep(tone1, time);
	  bbb_Beep(0, time);
	  bbb_Beep(tone2, time);
	  bbb_Beep(0, time);
	  bbb_Beep(tone3, time);
	  bbb_Beep(0, time);
}


